# -*- coding: utf-8 -*-
from logic import Circuit, Connection, IOCircuit,OrGate,AndGate,Multioutput
from comparators import BitCmpCircuit
from tools import *
import sys


class OddEvenMergeCirc(Circuit):
    def __init__(self,name,size,comparatorClass,linenames):
        Circuit.__init__(self,name)
        
        self.comparatorsSize = 0 
        
        # Create all input and outputs
        inputs = []
        outputs = []
        for inputId in xrange(0,size):
            inputs.append(self.connect(None,None))
            outputs.append(self.connect(None,None))

        if(size > 2):            
            even = size % 2 == 0 
            if even:
                maxLine = size-1
            else:
                maxLine = size
                
                
            # Create comparators and integrate them
            for i in xrange(1,maxLine,2):
                self.comparatorsSize += 1
                comparator = comparatorClass(linenames[i] + "-" + linenames[i+1])
                print "Comparator:" + linenames[i] + "-" + linenames[i+1]
                self.embedCircuit(comparator)
                inputs[i].setOutput(comparator.inputA)
                inputs[i+1].setOutput(comparator.inputB)
                comparator.outputMax.setOutput(outputs[i])
                comparator.outputMin.setOutput(outputs[i+1])
                
            
            inputs[0].setOutput(outputs[0])
            if(even):
                inputs[size-1].setOutput(outputs[size-1])                
                                        
        else:
            # Single comparator
            self.comparatorsSize += 1
            comparator = comparatorClass(linenames[0] + "-" + linenames[1])
            print "Comparator:" + linenames[0] + "-" + linenames[1]
            self.embedCircuit(comparator)
            inputs[0].setOutput(comparator.inputA)
            inputs[1].setOutput(comparator.inputB)
            comparator.outputMax.setOutput(outputs[0])
            comparator.outputMin.setOutput(outputs[1])
                            
        self.oddEvenInputs = inputs
        self.oddEvenOutputs = outputs    


class Generator(object):
    def __init__(self):
        self.comparatorSize = 0
    
    
    def generateOddEvenSort(self,size,comparatorClass,modify = False,reduce = False):
        # Create IO circuit
        circuit = IOCircuit("OESort_%d" % (size,))
        circuitInputs = []
        
        # Create all input and outputs
        inputs,outputs = self.__createIOConnections(circuit,size)
        
        # Generate circuit
        self.__generateOddEvenSortRec(0,size,comparatorClass,outputs,circuit,circuitInputs,modify,reduce)
        
        # Connect inputs to generated circuit inputs
        Connection.connectList(inputs, circuitInputs)
        
        print "Reducing unnecessary connections..."
        reducedNumber = circuit.reduceConnections()
        print "Removed %d connections" % reducedNumber
        
        print "Reducing unnecessary MultiOutputs..."
        reducedNumber = circuit.reduceMultioutputs()
        print "Removed %d MultiOutputs" % reducedNumber
        
        return circuit
        
                        
    def __generateOddEvenSortRec(self,
                                level,             # Level of recursion
                                size,              # Number of entries
                                comparatorClass,   # Class of comparator
                                connectToInputs,   # Connections that will be connected to outputs
                                circuitIO,         # Circuit object
                                circuitInputs,     # list of genateted inputs
                                modify,
                                reduce):
        if size < 2:
            circuitInputs += connectToInputs
            return 
        
        # Generate, modify and embed circuit
        oeMerge = self.generateOddEvenMerge(size, comparatorClass)
        if modify and size % 2 == 0 and size > 4:
            self.modify(oeMerge,size,reduce)
        circuitIO.embedCircuit(oeMerge)
        
        # Connect unziped inputs
        Connection.connectList(oeMerge.outputList,connectToInputs)
        if size % 2 == 0:                                                
            self.__generateOddEvenSortRec(level+1,size/2,comparatorClass,oeMerge.inputList[0:size/2],circuitIO,circuitInputs,modify,reduce)
            self.__generateOddEvenSortRec(level+1,size/2,comparatorClass,oeMerge.inputList[size/2:size],circuitIO,circuitInputs,modify,reduce)
        else:
            self.__generateOddEvenSortRec(level+1,size/2,comparatorClass,oeMerge.inputList[0:size/2],circuitIO,circuitInputs,modify,reduce)
            self.__generateOddEvenSortRec(level+1,size/2+1,comparatorClass,oeMerge.inputList[size/2:size],circuitIO,circuitInputs,modify,reduce)        
            
    def __createIOConnections(self,circuitIO,size):
        print "Creating IO connections..."
        inputs = []
        outputs = []
        for numberId in xrange(0,size):            
            inputs.append(circuitIO.createInput(circuitIO.name + "_I%d" % (numberId,),None))
            outputs.append(circuitIO.createOutput(circuitIO.name +"_O%d" % (numberId,),None))
        print "%d Input and %d Output connections created" % (size,size,)
        return (inputs,outputs,)
        
        
    
    def generateOddEvenMerge(self,size,comparatorClass):
        """ Generate odd-even merge circuitIO """
        print "----------------------------------------------"
        print "Generating odd even merge circuit... size:%d" % (size,)
                
        # Create IO circuit
        circuit = IOCircuit("OEMerge_%d" % (size,))        
        circuitInputs = []        
        
        # Create all input and outputs
        inputs,outputs = self.__createIOConnections(circuit,size)

        # Generate
        self.__generateOddEvenMergeRec(0, size, comparatorClass, zip(range(0,size),outputs), circuit, circuitInputs )
        
        print "Connecting inputs to created structure..."
        circuitInputs.sort()        
        Connection.connectList(inputs, listSumUnzip(circuitInputs))
        
        print "Reducing unnecessary connections..."
        reducedNumber = circuit.reduceConnections()
        print "Removed %d connections" % reducedNumber
        
        print "Reducing unnecessary MultiOutputs..."
        reducedNumber = circuit.reduceMultioutputs()
        print "Removed %d MultiOutputs" % reducedNumber
        
        print "Finished! %d gates, %d connections, %d*2 IO connections and %d comparators" % ( len(circuit.gateList),len(circuit.connectionList),size,self.comparatorSize)
        print "----------------------------------------------"
                
        return circuit 
    
    
    def __generateOddEvenMergeRec(self,
                                  level,
                                  size,
                                  comparatorClass,
                                  connectToInputs,
                                  circuitIO,
                                  circuitInputs):
        if(size < 2):
            print "Odd-even circuit of size 1, we got inputs!"
            circuitInputs += connectToInputs
            return

        print "Creating odd-even circuit of size %d..." % (size,)
        
        # Create oddEven circut and integrate it with outputs        
        oddEven = OddEvenMergeCirc("OEMergeRec_%d_%d" % (size,level),size,comparatorClass,[ str(x[0]) for x in connectToInputs ])
        circuitIO.embedCircuit(oddEven)
        
        # Connect unziped inputs
        Connection.connectList(oddEven.oddEvenOutputs,listSumUnzip(connectToInputs))
        
        print "Created and connected, %d comparators used" % (oddEven.comparatorsSize,)
        self.comparatorSize += oddEven.comparatorsSize
                    
        # Generate list of odd and even inputs
        evenInputs = []
        oddInputs = []            
        # Even case
        if(size % 2 == 0):
            # Dividable by 4 case
            if size % 4 == 0 or size < 4:
                for i in xrange(0,size):
                    if(i%2 == 0):
                        evenInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))                
                    else:
                        oddInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))                                    
            else:
                for i in xrange(0,size/2):
                    if(i%2 == 0):
                        evenInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))                
                    else:
                        oddInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))
 
                for i in xrange(size/2,size):
                    if(i%2 == 1):
                        evenInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))                
                    else:
                        oddInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))
        # Odd case
        else:
            if ((size - 1)/2) % 2 == 0:
                for i in xrange(0,size):
                    if(i%2 == 0):
                        evenInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))                
                    else:
                        oddInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))
            else:
                for i in xrange(0,size/2):
                    if(i%2 == 0):
                        evenInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))                
                    else:
                        oddInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))
 
                for i in xrange(size/2,size):
                    if(i%2 == 1):
                        evenInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))                
                    else:
                        oddInputs.append((connectToInputs[i][0], oddEven.oddEvenInputs[i], ))
                        
        self.__generateOddEvenMergeRec(level+1,len(evenInputs),comparatorClass,evenInputs,circuitIO,circuitInputs)
        self.__generateOddEvenMergeRec(level+1,len(oddInputs),comparatorClass,oddInputs,circuitIO,circuitInputs)        
                        
    #----------------------------------------- def extractLines(self,circuit,size):
        #------------------------------------------------------------------ lines = []
        #---------------------------------------------------- for x in xrange(0,size):
            #------------------------------------------------------------------ line = []
            #----------------------------------------- gate = circuit.inputList[x].output
            #------------------------------------------ line.append(circuit.inputList[x])
#------------------------------------------------------------------------------ 
            #---------------------------------------------------------------- while True:
                #--------------------------------------------------------- if(gate == None):
                    #-------------------------------------------------------------------- break
#------------------------------------------------------------------------------ 
                #------------------------------------------------- conn = gate.outputList[0]
                #--------------------------------------------------- if conn.output == None:
                    #-------------------------------------------------------- line.append(conn)
                    #-------------------------------------------------------------------- break
#------------------------------------------------------------------------------ 
                #--------------------------------- index = conn.output.inputList.index(conn)
                #----------------------------------------------------------- if(index == 0):
                    #-------------------------------------- conn = getNextGateConn(gate,OrGate)
                #--------------------------------------------------------------------- else:
                    #------------------------------------- conn = getNextGateConn(gate,AndGate)
#------------------------------------------------------------------------------ 
                #--------------------------------------------------------- line.append(conn)
                #-------------------------------------------------------- gate = conn.output
#------------------------------------------------------------------------------ 
            #--------------------------------------------------------- lines.append(line)
        #---------------------------------------------------------------- return lines
#------------------------------------------------------------------------------ 
#------------------------------------------------------------------------------ 
    def modify(self,circuit,size,reduct):
        print "----------------------------------------------"
        if reduct:
            print "Find shortcuts"        
            reductions = self.modifyFindShortcuts(circuit, size)
        else:
            reductions = None
        print "First half modification"
        self.modify1(circuit,size,reductions)
        print "Second half modification"
        self.modify2(circuit,size,reductions)
        reducedNumber = circuit.reduceConnections()
        print "Removed %d connections" % reducedNumber
        reducedNumber = circuit.reduceMultioutputs()
        print "Removed %d MultiOutputs" % reducedNumber
        print "----------------------------------------------"
            
    def modifyFindShortcuts(self,circuit,size):
        shortcuts = {}
        for x in xrange(0,size/2):
            # get First multioutput (it is always mo:)
            firstLevel = circuit.inputList[x].output
            
            # Get first level or gate
            flOrGate = getNextGateConn(firstLevel,OrGate).output
                
            # If it is direct link to output, there is nothing to do
            if( len(flOrGate.outputList) == 1):
                continue
            
            # ------------------------------------------------------
            # Reduction check no.2
            level = 0
            lastUpLevel = -1
            actGate = flOrGate
            while(True):            
                nextAndGateConn = getNextGateConn(actGate,AndGate)
                if(nextAndGateConn == None):
                    break
                nextOrGateConn = getNextGateConn(actGate,OrGate)
                if(nextOrGateConn == None):
                    break
                
                # We have found "go-up" line, sad thing...
                if(isInputB(nextAndGateConn,nextAndGateConn.output)):
                    lastUpLevel = level
                    actGate = nextAndGateConn.output                    
                elif(isInputA(nextOrGateConn,nextOrGateConn.output)):
                    actGate = nextOrGateConn.output                    
                level+=1            
            # ------------------------------------------------------
            print "Line " + str(x) + " level max: " + str(level) + " lastUpLevel: " + str(lastUpLevel)                    
            shortcuts[x] = (lastUpLevel,level) 
            
            
        for x in xrange(size/2,size):
            # get First multioutput (it is always mo:)
            firstLevel = circuit.inputList[x].output
            
            # Get first level or gate
            flAndGate = getNextGateConn(firstLevel,AndGate).output
                
            # Run to output, we do nothing here
            if( len(flAndGate.outputList) == 1):                
                continue 
            
            # ------------------------------------------------------
            # Reduction check no.2
            level = 0
            lastDownLevel = -1
            actGate = flAndGate
            while(True):            
                nextAndGateConn = getNextGateConn(actGate,AndGate)
                if(nextAndGateConn == None):
                    break
                nextOrGateConn = getNextGateConn(actGate,OrGate)
                if(nextOrGateConn == None):
                    break
                
                if(isInputA(nextOrGateConn,nextOrGateConn.output)):
                    lastDownLevel = level
                    actGate = nextOrGateConn.output                    
                elif(isInputB(nextAndGateConn,nextAndGateConn.output)):
                    actGate = nextAndGateConn.output                    
                level+=1            
            # ------------------------------------------------------
            print "Line " + str(x) + " level max: " + str(level) + " lastDownLevel: " + str(lastDownLevel)
            shortcuts[x] = (lastDownLevel,level)                             
            # ------------------------------------------------------        
        return shortcuts
                                    
    def modify1(self,circuit,size,reductions):                
        for x in xrange(0,size/2):
            
            # get First multioutput (it is always mo:)
            firstLevel = circuit.inputList[x].output
            
            # Get first level or gate
            flOrGate = getNextGateConn(firstLevel,OrGate).output
                
            # If it is direct link to output, there is nothing to do
            if( len(flOrGate.outputList) == 1):
                continue 
            
            # No modyfication here, full reduction :)
            
            if(reductions != None and reductions[x][0] == -1):
                print "Line: " + str(x) + ": full reduction, skiping modify" 
                continue
                                                                                                        
            # Remove OR gate
            slOrGateConnA = getNextGateConn(flOrGate,OrGate)
            slOrGate = slOrGateConnA.output
            slOrGateConnB = getOtherInput(slOrGate,slOrGateConnA)
            
            slOrGateConnA.output = None
            slOrGateConnB.output = None
            circuit.gateList.remove(slOrGate)
            
            paranelMO = Multioutput()
            circuit.addGate(paranelMO)            
            circuit.connect(slOrGateConnA,paranelMO)
            
            # Connect connB to OR gate outputs
            slOrGateMulti = Multioutput()
            circuit.addGate(slOrGateMulti)            
            circuit.connect(slOrGateConnB,slOrGateMulti)
            for outConn in slOrGate.outputList:
                outConn.input = None
                circuit.connect(slOrGateMulti,outConn)
            
            # Do we have reduction here??
            if(reductions != None and reductions[x][1] - reductions[x][0] > 1):
                print "Line: " + str(x) + ": reduction to level " + str(reductions[x][0])
                
                actGate = slOrGateMulti
                for x in xrange(0,reductions[x][0]):
                    conn = actGate.outputList[1]
                
                    while isinstance(conn.output,Connection):
                        conn = conn.output
                          
                    if(isInputB(conn,conn.output)):          
                        actGate = getNextGateConn(actGate, AndGate).output
                    elif(isInputA(conn,conn.output)):          
                        actGate = getNextGateConn(actGate, OrGate).output
                        
                # Disconnect connections to actGate
                nextOrGateConn = getNextGateConn(actGate, OrGate)
                nextOrGate = nextOrGateConn.output
                nextOrGateConn.input = None
                nextAndGateConn = getNextGateConn(actGate, AndGate)
                nextAndGate = nextAndGateConn.output
                nextAndGateConn.input = None                                                
                actGate.outputList = []
                
                # Create or gate
                outputOr = OrGate()
                circuit.addGate(outputOr)
            
                # Connect it to paranel line and actGate            
                circuit.connect(paranelMO, outputOr)
                circuit.connect(actGate, outputOr)
                circuit.connect(outputOr, nextAndGateConn)
                circuit.connect(outputOr, nextOrGateConn)
                continue                                
            
                
            # Find comparators that connect that line with lower gate
            gate = slOrGateMulti
            
            while True:                    
                if len(gate.outputList) == 1:
                    break
                            
                conn = gate.outputList[1]
                                
                while isinstance(conn.output,Connection):
                    conn = conn.output
                    
                if conn.output == None:
                    break
                
                index = conn.output.inputList.index(conn)
                if(index == 0):
                    print "Connecting to paranell line at " + str(x)
                    conn = getNextGateConn(gate,OrGate)
                    connB = getNextGateConn(gate,AndGate)
                    
                    nOrGate = OrGate()
                    circuit.addGate(nOrGate)
                    circuit.connect(paranelMO, nOrGate)
                    circuit.connect(gate, nOrGate)
                            
                    circuit.disconnect(gate,connB.output)                                        
                    circuit.connect(nOrGate,connB.output)
                    
                    # Swap inputList... god, have mercy on us...
                    tmp  = connB.output.inputList[0]
                    connB.output.inputList[0] = connB.output.inputList[1]
                    connB.output.inputList[1] = tmp 
                                        
                else:
                    conn = getNextGateConn(gate,AndGate)
                    
                gate = conn.output                            
            
            # Add Or gate to output
            
            # Remove output from lat gate            
            outputConn = circuit.outputList[x].getGateInput()
            outputGate = outputConn.input
            
            outputConn.input = None
            outputGate.removeOutput(outputConn)
            
            # Create or gate
            outputOr = OrGate()
            circuit.addGate(outputOr)
            
            # Connect it to paranel line and old output            
            circuit.connect(paranelMO,outputOr)
            circuit.connect(outputGate,outputOr)
            
            # Connect or gate to output
            outputConn.setInput(outputOr)


    def modify2(self,circuit,size,reductions):
        for x in xrange(size/2,size):
            firstLevel = circuit.inputList[x].output
            flAndGate = getNextGateConn(firstLevel,AndGate).output
                
            # Run to output, we do nothing here
            if( len(flAndGate.outputList) == 1):
                continue
            
            # No modyfication here, full reduction :)
            if(reductions != None and reductions[x][0] == -1):
                print "Line: " + str(x) + ": full reduction, skiping modify"
                continue
                         
            # Remove OR gate
            slAndGateConnB = getNextGateConn(flAndGate,AndGate)
            slAndGate = slAndGateConnB.output
            slAndGateConnA = getOtherInput(slAndGate,slAndGateConnB)
            
            slAndGateConnA.output = None
            slAndGateConnB.output = None
            circuit.gateList.remove(slAndGate)
                        
            paranelMO = Multioutput()
            circuit.addGate(paranelMO)            
            circuit.connect(slAndGateConnB,paranelMO)
            
            # Connect connB to OR gate outputs
            slAndGateMulti = Multioutput()
            circuit.addGate(slAndGateMulti)            
            circuit.connect(slAndGateConnA,slAndGateMulti)
            for outConn in slAndGate.outputList:
                outConn.input = None
                circuit.connect(slAndGateMulti,outConn)


            # Do we have reduction here??
            if(reductions != None and reductions[x][1] - reductions[x][0] > 1):
                print "Line: " + str(x) + ": reduction to level " + str(reductions[x][0])

                actGate = slAndGateMulti
                for x in xrange(0,reductions[x][0]):
                    conn = actGate.outputList[0]

                    while isinstance(conn.output,Connection):
                        conn = conn.output

                    if(isInputB(conn,conn.output)):
                        actGate = getNextGateConn(actGate, AndGate).output
                    elif(isInputA(conn,conn.output)):
                        actGate = getNextGateConn(actGate, OrGate).output

                # Disconnect connections to actGate
                nextOrGateConn = getNextGateConn(actGate, OrGate)
                nextOrGate = nextOrGateConn.output
                nextOrGateConn.input = None
                nextAndGateConn = getNextGateConn(actGate, AndGate)
                nextAndGate = nextAndGateConn.output
                nextAndGateConn.input = None                                                
                actGate.outputList = []
                
                # Create and gate
                outputAnd = AndGate()
                circuit.addGate(outputAnd)
            
                # Connect it to paranel line and actGate            
                circuit.connect(paranelMO, outputAnd)
                circuit.connect(actGate, outputAnd)
                circuit.connect(outputAnd, nextAndGateConn)
                circuit.connect(outputAnd, nextOrGateConn)
                continue
                        
            # Find comparators that connect that line with lower gate
            gate = slAndGateMulti

            while True:
                if len(gate.outputList) == 1:
                    break

                conn = gate.outputList[0]

                while isinstance(conn.output,Connection):
                    conn = conn.output

                if conn.output == None:
                    break

                index = conn.output.inputList.index(conn)
                if(index == 1):
                    print "Connecting to paranell line at " + str(x)
                    connB = getNextGateConn(gate,OrGate)
                    conn = getNextGateConn(gate,AndGate)

                    nAndGate = AndGate()
                    circuit.addGate(nAndGate)
                    circuit.connect(paranelMO, nAndGate)
                    circuit.connect(gate, nAndGate)

                    circuit.disconnect(gate,connB.output)
                    circuit.connect(nAndGate,connB.output)

                    # Swap inputList... god, have mercy on us...
                    tmp  = connB.output.inputList[0]
                    connB.output.inputList[0] = connB.output.inputList[1]
                    connB.output.inputList[1] = tmp

                else:
                    conn = getNextGateConn(gate,OrGate)

                gate = conn.output

            # Add Or gate to output

            #Remove output from lat gate
            outputConn = circuit.outputList[x].getGateInput()
            outputGate = outputConn.input

            outputConn.input = None
            outputGate.removeOutput(outputConn)

            # Create and gate
            outputAnd = AndGate()
            circuit.addGate(outputAnd)

            # Connect it to paranel line and old output
            circuit.connect(paranelMO,outputAnd)
            circuit.connect(outputGate,outputAnd)

            # Connect or gate to output
            outputConn.setInput(outputAnd)


def checkAllSortCombinations(circuit,size):
    for x in xrange(0,2**size):
        input = []
        trues = 0
        for i in xrange(0,size):
            if(2**i & x):
                input.append(True)
                trues+=1
            else:
                input.append(False)
        print "Input: " + str(input)
        output = circuit.execute(input)
        outputTrue = 0
        for x in output:
            if x:
                outputTrue+=1
        if(trues == outputTrue):
            print "OK"
        else:
            print "WRONG!"
            return        

def checkAllMergeCombinations(circuit,size):
    if(size % 2 == 0):
        leftSize = size/2
        rightSize = size/2
    else:
        leftSize =  size/2
        rightSize =  size/2+1
    
    for x in xrange(0,leftSize+1):
        input1 = []
        trues1 = 0
        for i in xrange(0,leftSize):
            if(i < x):
                input1.append(True)
                trues1+=1
            else:
               input1.append(False)
               
        for y in xrange(0,rightSize+1):
            input = input1[:]
            trues = trues1
            for i in xrange(0,rightSize):
                if(i < y):
                    input.append(True)
                    trues+=1
                else:
                   input.append(False)
        
               
            print "Input: " + str(input)
            output = circuit.execute(input)
            outputTrue = 0
            outputFalseSpoted = False
            for x in output:
                if x:
                    if(outputFalseSpoted):
                        print "WRONG!"
                        return
                    outputTrue+=1
                else:
                    outputFalseSpoted = True
                    
            if(trues == outputTrue):
                print "OK"
            else:
                print "WRONG!"
                return        
                    
                    
def cliError():
    print "Usage: python generator.py SIZE TYPE MODIFY REDUCTION TEST_VECTOR"
    print "SIZE = numer of bits"
    print "TYPE = (Merge|Sort)"
    print "MODIFY = True|False"
    print "REDUCTION = True|False"
    print "TEST_VECTOR = Vector to be tested ([01]*) or ALL for testing all vectors"
    sys.exit(1)                
        
if __name__ == '__main__':
    if len(sys.argv) < 3:
        cliError()
        
        
    # Get params
    size = int(sys.argv[1])
    type = sys.argv[2]
    
    if len(sys.argv) >= 4:
        modify = (sys.argv[3] == "True")
    else:
        modify = False
        
    if len(sys.argv) >= 5:
        reduction = (sys.argv[4] == "True")
    else:
        reduction = False
        
    if len(sys.argv) >= 6:
        testVector = sys.argv[5]
    else:
        testVector = False
        
        
    gen = Generator()
    if(type.upper() == "MERGE"):
        circut = gen.generateOddEvenMerge(size,BitCmpCircuit)
        if modify:
            gen.modify(circut, size,reduction)            
    elif(type.upper() == "SORT"):
        circut = gen.generateOddEvenSort(size,BitCmpCircuit,modify,reduction)
    else:
        cliError()
    
    if testVector != False:
        if testVector.upper() == "ALL":
            if(type.upper() == "MERGE"):        
                checkAllMergeCombinations(circut,size)
            elif(type.upper() == "SORT"):
                checkAllSortCombinations(circut,size)
        else:
            t = []
            for x in testVector:
                if x == "1":
                    t.append(True)
                else:
                    t.append(False)
            circut.execute(t)
